From 95ea1d92ca02cfe0ff0401aa806165bbf090e5f6 Mon Sep 17 00:00:00 2001 From: "cl349@freefall.cl.cam.ac.uk" Date: Mon, 19 Jul 2004 22:01:02 +0000 Subject: [PATCH] bitkeeper revision 1.1108.3.1 (40fc449eExRZSW5dU1TAzdlOTRDqMQ) Add HYPERVISOR_block support. Not enabled yet since it adds a 5 seconds long delay during boot. --- linux-2.6.7-xen-sparse/arch/xen/Kconfig | 4 + .../arch/xen/i386/kernel/time.c | 101 +++++++++++++++++- .../arch/xen/kernel/process.c | 11 +- 3 files changed, 110 insertions(+), 6 deletions(-) diff --git a/linux-2.6.7-xen-sparse/arch/xen/Kconfig b/linux-2.6.7-xen-sparse/arch/xen/Kconfig index 659a577755..b102b2e183 100644 --- a/linux-2.6.7-xen-sparse/arch/xen/Kconfig +++ b/linux-2.6.7-xen-sparse/arch/xen/Kconfig @@ -16,6 +16,10 @@ config ARCH_XEN default y +config NO_IDLE_HZ + bool + default y + source "init/Kconfig" #config VT diff --git a/linux-2.6.7-xen-sparse/arch/xen/i386/kernel/time.c b/linux-2.6.7-xen-sparse/arch/xen/i386/kernel/time.c index 66b1aff9d9..bc705c8d66 100644 --- a/linux-2.6.7-xen-sparse/arch/xen/i386/kernel/time.c +++ b/linux-2.6.7-xen-sparse/arch/xen/i386/kernel/time.c @@ -87,6 +87,17 @@ EXPORT_SYMBOL(i8253_lock); struct timer_opts *cur_timer = &timer_none; +/* These are peridically updated in shared_info, and then copied here. */ +static u32 shadow_tsc_stamp; +static u64 shadow_system_time; +static u32 shadow_time_version; +static struct timeval shadow_tv; + +/* Keep track of last time we did processing/updating of jiffies and xtime. */ +static u64 processed_system_time; /* System time (ns) at last processing. */ + +#define NS_PER_TICK (1000000000ULL/HZ) + /* * This version of gettimeofday has microsecond resolution * and better than microsecond precision on fast x86 machines with TSC. @@ -203,6 +214,24 @@ unsigned long long monotonic_clock(void) EXPORT_SYMBOL(monotonic_clock); +/* + * Reads a consistent set of time-base values from Xen, into a shadow data + * area. Must be called with the xtime_lock held for writing. + */ +static void __get_time_values_from_xen(void) +{ + do { + shadow_time_version = HYPERVISOR_shared_info->time_version2; + rmb(); + shadow_tv.tv_sec = HYPERVISOR_shared_info->wc_sec; + shadow_tv.tv_usec = HYPERVISOR_shared_info->wc_usec; + shadow_tsc_stamp = HYPERVISOR_shared_info->tsc_timestamp.tsc_bits; + shadow_system_time = HYPERVISOR_shared_info->system_time; + rmb(); + } + while ( shadow_time_version != HYPERVISOR_shared_info->time_version1 ); +} + /* * timer_interrupt() needs to keep up the real-time clock, * as well as call the "do_timer()" routine every clocktick @@ -210,6 +239,9 @@ EXPORT_SYMBOL(monotonic_clock); static inline void do_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { + s64 delta; + unsigned long ticks = 0; + #ifdef CONFIG_X86_IO_APIC if (timer_ack) { /* @@ -226,7 +258,23 @@ static inline void do_timer_interrupt(int irq, void *dev_id, } #endif - do_timer_interrupt_hook(regs); + __get_time_values_from_xen(); + + delta = (s64)(shadow_system_time - processed_system_time); + if (delta < 0) { + printk("Timer ISR: Time went backwards: %lld\n", delta); + return; + } + + /* Process elapsed jiffies since last call. */ + while (delta >= NS_PER_TICK) { + ticks++; + delta -= NS_PER_TICK; + processed_system_time += NS_PER_TICK; + + if (regs) + do_timer_interrupt_hook(regs); + } #if 0 /* XEN PRIV */ /* @@ -288,8 +336,7 @@ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) cur_timer->mark_offset(); - if (regs) /* XXXcl check regs in do_timer_interrupt */ - do_timer_interrupt(irq, NULL, regs); + do_timer_interrupt(irq, NULL, regs); write_sequnlock(&xtime_lock); return IRQ_HANDLED; @@ -410,3 +457,51 @@ void __init time_init(void) (void)setup_irq(time_irq, &irq_timer); } + +/* Convert jiffies to system time. Call with xtime_lock held for reading. */ +static inline u64 __jiffies_to_st(unsigned long j) +{ + return processed_system_time + ((j - jiffies) * NS_PER_TICK); +} + +/* + * This function works out when the the next timer function has to be + * executed (by looking at the timer list) and sets the Xen one-shot + * domain timer to the appropriate value. This is typically called in + * cpu_idle() before the domain blocks. + * + * The function returns a non-0 value on error conditions. + * + * It must be called with interrupts disabled. + */ +extern spinlock_t timerlist_lock; +int set_timeout_timer(void) +{ + struct timer_list *timer; + u64 alarm = 0; + int ret = 0; + + spin_lock(&timerlist_lock); + + /* + * This is safe against long blocking (since calculations are not based on + * TSC deltas). It is also safe against warped system time since + * suspend-resume is cooperative and we would first get locked out. It is + * safe against normal updates of jiffies since interrupts are off. + */ + alarm = __jiffies_to_st(next_timer_interrupt()); + +#if 0 + /* Tasks on the timer task queue expect to be executed on the next tick. */ + if ( TQ_ACTIVE(tq_timer) ) + alarm = __jiffies_to_st(jiffies + 1); +#endif + + /* Failure is pretty bad, but we'd best soldier on. */ + if ( HYPERVISOR_set_timer_op(alarm) != 0 ) + ret = -1; + + spin_unlock(&timerlist_lock); + + return ret; +} diff --git a/linux-2.6.7-xen-sparse/arch/xen/kernel/process.c b/linux-2.6.7-xen-sparse/arch/xen/kernel/process.c index a6930ee971..c884a02757 100644 --- a/linux-2.6.7-xen-sparse/arch/xen/kernel/process.c +++ b/linux-2.6.7-xen-sparse/arch/xen/kernel/process.c @@ -10,11 +10,16 @@ void xen_cpu_idle (void) { - // local_irq_disable(); + local_irq_disable(); if (need_resched()) { - // local_irq_enable(); + local_irq_enable(); return; } - // local_irq_enable(); + if (0 && set_timeout_timer() == 0) { + /* NB. Blocking reenable events in a race-free manner. */ + HYPERVISOR_block(); + return; + } + local_irq_enable(); HYPERVISOR_yield(); } -- 2.30.2